package m3f.data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import m3f.computing.RandomNumbers;
import m3f.io.MatrixReader;
import m3f.io.MatrixReaderFactory;
import m3f.matrix.Minibatch;
import m3f.matrix.SparseVector;

public class SingleDataSet implements SingleDataProvider {
	
	private ArrayList<SparseVector> vectors;
	private int features;
	private int totalSamples;
	private ArrayList<Integer> sample;
	private int minibatch;
	private int pointer;
	
	public SingleDataSet(String file, boolean normalizeVectors){
		init(file, true, normalizeVectors);
	}
	
	public SingleDataSet(String file, int features, boolean normalizeVectors){
		this.features = features;
		init(file, false, normalizeVectors);
	}
	
	private void init(String file, boolean overrideFeatures, boolean normalizeVectors){
		MatrixReader reader = MatrixReaderFactory.newInstance(file, normalizeVectors);
		reader.start(file);
		if(overrideFeatures) {
			features = reader.getMatrixColumns();
		}
		totalSamples = reader.getMatrixRows();
		System.out.println("totalSamples:" + totalSamples + " features:" + features);
		sample = new ArrayList<Integer>();
		for(int k = 0; k < totalSamples; k++){
			sample.add(k);
		}
		System.out.println("sample:" + sample.size());
		vectors = reader.readVectors(sample.size());
		pointer = 0;
		System.out.println("vectors:" + vectors.size());	
	}
	
	
	public Minibatch fullBatch() {
		Minibatch mb = new Minibatch(features, totalSamples);
		for(int k = 0; k < totalSamples; k++){
			mb.setColumn(k, vectors.get(sample.get(k)));
		}
		return mb;
	} 

	@Override
	public boolean hasMoreData() {
		return pointer < totalSamples;
	}

	@Override
	public Minibatch next() {
		int size = minibatch;
		if(pointer + minibatch > totalSamples){
			size = totalSamples - pointer;
		}
		Minibatch mb = new Minibatch(features, size);
		for(int k = 0; k < minibatch && pointer < totalSamples; k++){
			mb.setColumn(k, vectors.get(sample.get(pointer)));
			pointer++;
		}
		return mb;
	}

	@Override
	public void reset(boolean randomized) {
		sample = new ArrayList<Integer>();
		for(int i = 0; i < totalSamples; i++){
			sample.add(i);
		}
		Random rnd = RandomNumbers.getInstance();
		if(randomized){
			Collections.shuffle(sample, rnd);
		}
	}

	@Override
	public void setMinibatchSize(int size) {
		this.minibatch = size;
	}

	@Override
	public int getMinibatchSize() {
		return this.minibatch;
	}

	@Override
	public int matrixRows() {
		return totalSamples;
	}

	@Override
	public int features() {
		return features;
	}
}
